﻿using System;
using System.Collections.Generic;

namespace sharpxbot.Core.Security
{
    public class UsageCounter : IUsageCounter
    {
        public const int DefaultTimeLimit = 30;
        public const int DefaultCounterLimit = 3000;

        public UsageCounter(int counterLimit) : this(counterLimit, DefaultTimeLimit) { }

        public UsageCounter(int counterLimit, int timeLimitMs)
        {
            if (counterLimit <= 0)
                throw new ArgumentException("Illegal counter limit. Must be positive");

            if (timeLimitMs <= 0)
                throw new ArgumentException("Illegal time limit. Must be positive");


            this.CounterLimit = counterLimit;
            this.TimeLimit = new TimeSpan(0, 0, 0, 0, timeLimitMs);

            executionsQueue = new Queue<DateTime>();
        }

        #region IUsageCounter Members

        public void Perform()
        {
            int totalItemsCount = GetCurrentItemsCount();

            DateTime currentDateTime = DateTime.Now;

            if (totalItemsCount == 0)
            {
                minDate = currentDateTime;
                maxDate = currentDateTime;
            }
            else
            {
                maxDate = currentDateTime;

                if (totalItemsCount > CounterLimit)
                {
                    executionsQueue.Dequeue();
                    minDate = executionsQueue.Peek();
                }
            }

            executionsQueue.Enqueue(currentDateTime);
        }

        public bool ExceedesLimit
        {
            get { return ExceedesLimitImpl(); }
        }

        public TimeSpan TimeLimit { get; set; }

        public int CounterLimit { get; set; }

        #endregion

        private int GetCurrentItemsCount()
        {
            return executionsQueue.Count;
        }

        private bool ExceedesLimitImpl()
        {
            bool queueIsFull = GetCurrentItemsCount() == CounterLimit;
            TimeSpan delta = maxDate.Subtract(minDate);

            return queueIsFull && (delta < TimeLimit);
        }

        DateTime minDate, maxDate;

        Queue<DateTime> executionsQueue;
    }
}
